package com.hup.winHolderService.ws.tomcat;

import com.hup.utils.commons.start.SpringContext;
import com.hup.winHolderService.ws.WsClient;
import com.hup.winHolderService.ws.WsClientHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * <pre>
 * 基于Tomcat的websocket的实现类
 * .本类只做tomcat框架代码适配, 不实现[框架,业务]功能
 * //
 * .注意,本类不是单例,是多实例,不能用 Autowired
 * .app启动时创建的实例: 由[@Service]触发,用于处理ServerEndpoint的建立连接
 * .后续每个client都会创建新实例!
 * https://blog.csdn.net/qq_44938451/article/details/121196983
 *
 * @author hugan
 * @date 2022/5/18
 */
@Slf4j
@Service
@ServerEndpoint("/ws")
public class TomcatWebsocketClient extends WsClient {

    private final WsClientHandler clientHandler;
    private Session session;

    public TomcatWebsocketClient() {
        //log.info("newTomcatWebsocketClient");
        //每个client都会new一次
        clientHandler = SpringContext.getBean(WsClientHandler.class);
    }

    /**
     * 前端初始化websocket,访问 {@link ServerEndpoint} 地址时到达
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        clientHandler.onConnected(this, session);
    }

    /**
     * 触发情况:
     * .关闭浏览器
     * .onOpen时抛出异常
     */
    @OnClose
    public void onClose(CloseReason reason) {
        clientHandler.onClosed(this, reason);
    }

    @OnError
    public void onError(Throwable e) {
        clientHandler.onError(this, e);
    }

    @Override
    public void sendPing() throws IOException {
        session.getAsyncRemote().sendPing(ByteBuffer.allocate(0));
    }

    @Override
    public void doCloseSilent() {
        try {
            session.close();
        } catch (IOException ignored) {
        }
    }

    /**
     * 实现心跳功能:
     * https://www.it610.com/article/1280176624142139392.htm
     * ..一般来说只有服务端给客户端发送Ping，然后客户端发送Pong来回应
     * 谷歌浏览器会自动回复[收到的ping数据]
     */
    @OnMessage
    public void onMessage(@SuppressWarnings("unused") PongMessage msg) {
        clientHandler.onPongMessage(this);
    }

    /**
     * @deprecated 不直接收发字符串, 都发byte[]
     */
    @OnMessage
    public void onMessage(String msg) {
        clientHandler.onMessage(msg, this);
    }

    /**
     * 注意:
     * msg最大长度,在BTomcatBeanConfig配置; 省缺为 8192
     * 注意: 一旦前端发送过长的数据,就会马上断开,触发onClose!!!
     */
    @OnMessage
    public void onMessage(byte[] msg) {
        clientHandler.onMessage(msg, this);
    }

    @Override
    public void sendText(String toSend) {
        session.getAsyncRemote().sendText(toSend);
    }

}
